package com.eistert.java.algorithm.greedy;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;

/**
 * @Description: 贪心算法
 * @Author: ai
 * @create: 2023-04-26 18:47
 */
public class GreedyAlgorithm {

    /**
     *贪心算法介绍
     * 1.贪心算法是指在对问题进行求解时，
     * 在每一步选择中都采取最好或者最优（即最优）的选择，从而希望能够能够导致结果是最好或者最优的算法。
     *
     * 2.贪心算法所得到的结果不一定是最优的结果，有时候会是最优解，但是都是相对近似（接近）最优解的结果。
     */

    /**
     * 问题解决思路
     * 1.目前并没有算法可以快速计算得到准备的值，使用贪婪算法，则可以得到非常接近的解，并且效率高，
     * 选择策略上，因为需要覆盖全部地区的最小集合；
     * <p>
     * 2.遍历所有的广播电台，找到一个覆盖了最多未覆盖的地区的电台，此电台可能包含一些已覆盖的地区，但没有关系。
     * <p>
     * 3.将这个电台加入到一个集合中，想办法把该电台覆盖的地区在下次比较时去掉。
     * <p>
     * 4.重复第一步直到覆盖了全部的地区。
     */
    public static void main(String[] args) {
        // 获取所有的广播电台
        HashMap<String, HashSet<String>> broadcasts = getBroadcasts();
        // 获取所有的地区
        HashSet<String> allAreas = getAllAreas();

        // 存放选择的电台集合
        ArrayList<String> selectedList = new ArrayList<>();
        // 定义一个临时的集合，在遍历的过程中，存放遍历过程中的电台覆盖的地区和当前还没有覆盖的地区的交集
        HashSet<String> tempSet = new HashSet<>();

        // 定义maxKey，保存在一次遍历过程中，能够覆盖最大未覆盖的地区对应的电台的key
        String maxKey = null;

        while (allAreas.size() != 0) { // 如果allAreas不为0，则表示还没有覆盖到所有地区
            // 每进行一次while，需要将maxkey置为null
            maxKey = null;

            // 遍历broadcasts,取出对应key
            for (String key : broadcasts.keySet()) {
                // 每进行一个循环，需要将tempSet清空
                tempSet.clear();

                // 当前这个key能够覆盖的地区
                HashSet<String> areas = broadcasts.get(key);
                tempSet.addAll(areas);

                // 求出tempSet 和 allAreas 集合的交集，交集会赋给tempSet
                tempSet.retainAll(allAreas);

                /**
                 * 如果当前这个集合包含的未覆盖地区的数量，比maxKey指向的集合地区还多，就需要重置maxKey
                 *
                 * tempSet.size() >broadcasts.get(maxKey).size()) 体现出贪心算法的特点,每次都选择最优的
                 */
                if (tempSet.size() > 0 && (maxKey == null ||
                        tempSet.size() > broadcasts.get(maxKey).size())) {
                    maxKey = key;
                }
            }

            // maxKey != null，就应该将maxKey加入到 selects
            if (maxKey != null) {
                selectedList.add(maxKey);

                // 将maxKey指向的广播电台覆盖的地区，从allAreas去掉
                allAreas.removeAll(broadcasts.get(maxKey));
            }
        }

        /**
         * [K1, K2, K3, K5]
         */
        System.out.println("得到的选择结果是 selectedList --> " + selectedList);

    }

    /**
     * 获取所有的广播电台
     */
    private static HashMap<String, HashSet<String>> getBroadcasts() {
        // 创建广播电台,放入到 Map
        HashMap<String, HashSet<String>> broadcasts = new HashMap<>();

        // 将各个电台放入到 broadcasts
        HashSet<String> broadcast1 = new HashSet<>();
        broadcast1.add("北京");
        broadcast1.add("上海");
        broadcast1.add("天津");

        HashSet<String> broadcast2 = new HashSet<>();
        broadcast2.add("广州");
        broadcast2.add("北京");
        broadcast2.add("深圳");

        HashSet<String> broadcast3 = new HashSet<>();
        broadcast3.add("成都");
        broadcast3.add("上海");
        broadcast3.add("杭州");

        HashSet<String> broadcast4 = new HashSet<>();
        broadcast4.add("上海");
        broadcast4.add("天津");

        HashSet<String> broadcast5 = new HashSet<>();
        broadcast5.add("杭州");
        broadcast5.add("大连");

        // 加 入 到 map
        broadcasts.put("K1", broadcast1);
        broadcasts.put("K2", broadcast2);
        broadcasts.put("K3", broadcast3);
        broadcasts.put("K4", broadcast4);
        broadcasts.put("K5", broadcast5);

        return broadcasts;
    }

    /**
     * 获取所有的地区
     */
    private static HashSet<String> getAllAreas() {
        // allAreas 存放所有的地区
        HashSet<String> allAreas = new HashSet<String>();
        allAreas.add("北京");
        allAreas.add("上海");
        allAreas.add("天津");
        allAreas.add("广州");
        allAreas.add("深圳");
        allAreas.add("成都");
        allAreas.add("杭州");
        allAreas.add("大连");

        return allAreas;
    }

}
